<?php
namespace App\Http\Controllers\Front;

use App\Service\Front\PayService;
use Illuminate\Http\Request;

class PayWxController1120 extends BaseController
{
    //支付

    //必须的参数
    protected $app_id = 'wx4171136552ce7ceb'; //'wx8ead28aa79ce8683'; //appid
    protected $mch_id = '1691588547'; //商户号
    protected $key = 'karcvn1113mj1yfysww0dzcnbic4ec8r'; //秘钥
    protected $notify_url = ''; //通知接口
    //微信证书序列号：4A730B76F65D8C40C82BB1DB4B288D07E3B180BE

    public function __construct(PayService $service)
    {
        $this->db = $service;
        $this->notify_url = env('DOMAIN') . '/api/front/pay/wx/notice';
    }

    //测试支付
    public function test()
    {
        $orderno = toOrderno();
        $amount = 1;
        $nonce = toOrderno();
        $userIp = $this->getUserIp();
        $openid = '0000';
        //构建签名
        $signs = [
            'appid' => $this->app_id,
            'mch_id' => $this->mch_id,
            'nonce_str' => $nonce,
            'body' => 'order',
            'notify_url' => $this->notify_url,
            'out_trade_no' => $orderno,
            'spbill_create_ip' => $userIp,
            'total_fee' => $amount,
            'trade_type' => 'JSAPI',
            'sign_type' => 'MD5',
            'openid' => $openid,
        ];
        ksort($signs);
        var_dump($signs); echo '<br>1';
        $string = '';
        foreach ($signs as $k => $v) {
            if ($v) {
                $string .= $k . '=' . $v . '&';
            }
        }
        $string .= 'key=' . $this->key;
        var_dump($string); echo '<br>2';
        $signStr = strtoupper(md5($string));
        var_dump($signStr); echo '<br>3';
        //构建请求参数
        $param = '';
        $param .= '<xml>';
        $param .= '<appid>' . $this->app_id . '</appid>';
        $param .= '<body>' . $signs['body'] . '</body>';
        $param .= '<mch_id>' . $this->mch_id . '</mch_id>';
        $param .= '<nonce_str>' . $nonce . '</nonce_str>';
        $param .= '<notify_url>' . $this->notify_url . '</notify_url>';
        $param .= '<out_trade_no>' . $orderno . '</out_trade_no>';
        $param .= '<spbill_create_ip>' . $userIp . '</spbill_create_ip>';
        $param .= '<total_fee>' . $amount . '</total_fee>';
        $param .= '<trade_type>' . $signs['trade_type'] . '</trade_type>';
        $param .= '<openid>' . $signs['openid'] . '</openid>';
        $param .= '<sign_type>' . $signs['sign_type'] . '</sign_type>';
        $param .= '<sign>' . $signStr . '</sign>';
        $param .= '</xml>';
        var_dump($param); echo '<br>4';
        $httpUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $res = $this->toCurl($httpUrl, $param, 1);
        var_dump($res); echo '<br>5';
    }

    /**
     * 微信支付：统一下单
     * https://api.mch.weixin.qq.com/pay/unifiedorder
     */
    public function wxPay(Request $request)
    {
        $token = $request->post('token', ''); //登录token
        $type = $request->post('type', 1); //1原创需求订单
        $orderno = $request->post('orderno', 0); //订单号
        $orderOne = $this->db->orderPrice($type, $orderno);
        if (empty($orderOne)) {
            return $this->toJson(-2, '订单错误');
        }
        $uOne = $this->db->userByToken($token);
        if (!$uOne) {
            return $this->toJson(-2, '未登录');
        }
        $uid = $uOne['id'];
        $openid = $uOne['openid'];
        $userIp = $this->getUserIp();
        $nonce = $orderOne['orderno'];
        $amount = $orderOne['price'];
        //构建签名
        $signs = [
            'appid' => $this->app_id,
            'mch_id' => $this->mch_id,
            'nonce_str' => $nonce,
            'body' => 'order',
            'notify_url' => $this->notify_url,
            'out_trade_no' => $orderno,
            'spbill_create_ip' => $userIp,
            'total_fee' => $amount,
            'trade_type' => 'JSAPI',
            'sign_type' => 'MD5',
            'openid' => $openid,
        ];
        ksort($signs);
//        var_dump($signs); echo '<br>1';
        $string = '';
        foreach ($signs as $k => $v) {
            if ($v) {
                $string .= $k . '=' . $v . '&';
            }
        }
        $string .= 'key=' . $this->key;
//        var_dump($string); echo '<br>2';
        $payData = [
            'uid' => $uid, 'from_type' => $type,
            'out_trade_no' => $orderno, 'money' => $amount,
            'order_sign' => $string,
        ];
        $lastid = $this->db->wxPayAdd($payData); //支付log
        $signStr = strtoupper(md5($string));
//        var_dump($signStr); echo '<br>3';
        //构建请求参数
        $param = '';
        $param .= '<xml>';
        $param .= '<appid>' . $this->app_id . '</appid>';
        $param .= '<body>' . $signs['body'] . '</body>';
        $param .= '<mch_id>' . $this->mch_id . '</mch_id>';
        $param .= '<nonce_str>' . $nonce . '</nonce_str>';
        $param .= '<notify_url>' . $this->notify_url . '</notify_url>';
        $param .= '<out_trade_no>' . $orderno . '</out_trade_no>';
        $param .= '<spbill_create_ip>' . $userIp . '</spbill_create_ip>';
        $param .= '<total_fee>' . $amount . '</total_fee>';
        $param .= '<trade_type>' . $signs['trade_type'] . '</trade_type>';
        $param .= '<openid>' . $signs['openid'] . '</openid>';
        $param .= '<sign_type>' . $signs['sign_type'] . '</sign_type>';
        $param .= '<sign>' . $signStr . '</sign>';
        $param .= '</xml>';
//        var_dump($param); echo '<br>4';
        $this->db->wxPayModify($lastid, ['order_req'=>$param]);
        $httpUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $res = $this->toCurl($httpUrl, $param, 1);
//        var_dump($res); echo '<br>5';
        $payData = [
            'order_back' => json_encode($res, JSON_UNESCAPED_UNICODE),
        ];
        $this->db->wxPayModify($lastid, $payData); //支付log
        if ($res['code'] < 0) {
            return $this->toJson(-2, $res['msg']);
        }
        //用于唤起的参数
        $resData = [
            'appId' => $this->app_id,
            'timeStamp' => (string) time(),
            'nonceStr' => toOrderno(),
            'package' => 'prepay_id=' . $res['data']['prepay_id'],
            'signType' => 'MD5',
        ];
        ksort($resData);
        $string = '';
        foreach ($resData as $k => $v) {
            if ($v) {
                $string .= $k . '=' . $v . '&';
            }
        }
        $string .= 'key=' . $this->key;
        $resData['mchId'] = $this->mch_id;
        $resData['orderInfo'] = '案例需求订单';
        $resData['key'] = $this->key;
        $resData['paySign'] = strtoupper(md5($string));
        $payData = [
            'pay_info' => json_encode($resData, JSON_UNESCAPED_UNICODE),
            'status' => 1,
        ];
        $this->db->wxPayModify($lastid, $payData); //支付log
        return $this->toJson(0, '', $resData);
    }

    //微信通知
    public function notice()
    {
        $xml = file_get_contents('php://input');
        $lastid = $this->db->wxNotice($xml);
        $prefix = '<![CDATA['; $suffix = ']]>';
        //return_code
        $res = preg_match('/<return_code>(.*?)<\/return_code>/', $xml, $matches);
        if (!$res) {
            return $this->toJson(-2, 'return_code 缺失');
        }
        $return_code = $matches[1];
        if (substr($return_code, 0, strlen($prefix)) == $prefix) {
            $return_code = substr($return_code, 9);
        }
        if (substr($return_code, -3) == $suffix) {
            $return_code = substr($return_code, 0, -3);
        }
        if ($return_code != 'SUCCESS') {
            return $this->toJson(-2, '通信失败');
        }
        $items['return_code'] = $return_code;
        //result_code
        $res = preg_match('/<result_code>(.*?)<\/result_code>/', $xml, $matches);
        if (!$res) {
            return $this->toJson(-2, 'result_code 缺失');
        }
        $result_code = $matches[1];
        if (substr($result_code, 0, strlen($prefix)) == $prefix) {
            $result_code = substr($result_code, 9);
        }
        if (substr($result_code, -3) == $suffix) {
            $result_code = substr($result_code, 0, -3);
        }
        if ($result_code != 'SUCCESS') {
            return $this->toJson(-2, '交易失败');
        }
        $items['result_code'] = $return_code;
        //out_trade_no
        $res = preg_match('/<out_trade_no>(.*?)<\/out_trade_no>/', $xml, $matches);
        if (!$res) {
            return $this->toJson(-2, 'out_trade_no 缺失');
        }
        $out_trade_no = $matches[1];
        if (substr($out_trade_no, 0, strlen($prefix)) == $prefix) {
            $out_trade_no = substr($out_trade_no, 9);
        }
        if (substr($out_trade_no, -3) == $suffix) {
            $out_trade_no = substr($out_trade_no, 0, -3);
        }
        $items['out_trade_no'] = $out_trade_no;
        $this->db->wxNoticeModify($lastid, $out_trade_no);
        return $this->toJson(0, '', $items);
    }

//    //退款
//    public function refund(Request $request)
//    {
//        $token = $request->post('token', '');
//        $orderno = $request->post('orderno', '');
//        $uid = $this->db->uidByToken($token);
//        if (!$uid) {
//            return $this->toJson(-2, '没有登录');
//        }
//        $res = $this->db->refundOrderOne($orderno);
//        if ($res['code'] < 0) {
//            return $this->toJson(-2, $res['msg']);
//        }
//        $payWay = $res['data']['payWay'];
//        $type = $res['data']['type'];
//        $realPay = $res['data']['realPay'];
//        if ($payWay == 2) {
//            $res = $this->db->refundBalance($uid, $orderno, $realPay);
//        } else {
//            $res = $this->wxRefund($uid, $orderno, $realPay);
//        }
//        if ($res['code'] < 0) {
//            return $this->toJson(-2, $res['msg']);
//        }
//        return $this->toJson();
//    }

//    //退款，提供后台调用
//    public function refundByAuth($uid, $orderno)
//    {
//        $res = $this->db->refundOrderOne($orderno);
//        if ($res['code'] < 0) {
//            return $this->toJson(-2, $res['msg']);
//        }
//        $payWay = $res['data']['payWay'];
//        $type = $res['data']['type'];
//        $realPay = $res['data']['realPay'];
//        if ($payWay == 2) {
//            $res = $this->db->refundBalance($uid, $orderno, $realPay);
//        } else {
//            $res = $this->wxRefund($uid, $orderno, $realPay);
//        }
//        if ($res['code'] < 0) {
//            return $this->toJson(-2, $res['msg']);
//        }
//        return $this->toJson();
//    }
//
//    //微信退款
//    public function wxRefund($uid, $orderno, $amount)
//    {
//        //https://api.mch.weixin.qq.com/secapi/pay/refund
//        $httpUrl = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
//        $nonce = toOrderno();
//        $out_refund_no = toOrderno();
//        $signs = [
//            'appid' => $this->app_id,
//            'mch_id' => $this->mch_id,
//            'nonce_str' => $nonce,
//            'notify_url' => $this->notify_url2,
//            'out_refund_no' => $out_refund_no,
//            'out_trade_no' => $orderno,
//            'total_fee' => $amount,
//            'refund_fee' => $amount,
//            'sign_type' => 'MD5',
//        ];
//        ksort($signs);
//        $string = '';
//        foreach ($signs as $k => $v) {
//            if ($v) {
//                $string .= $k . '=' . $v . '&';
//            }
//        }
//        $string .= 'key=' . $this->key;
//        $signStr = strtoupper(md5($string));
//        //构建请求参数
//        $param = '';
//        $param .= '<xml>';
//        $param .= '<appid>' . $this->app_id . '</appid>';
//        $param .= '<mch_id>' . $this->mch_id . '</mch_id>';
//        $param .= '<nonce_str>' . $nonce . '</nonce_str>';
//        $param .= '<notify_url>' . $this->notify_url2 . '</notify_url>';
//        $param .= '<out_refund_no>' . $out_refund_no . '</out_refund_no>';
//        $param .= '<out_trade_no>' . $orderno . '</out_trade_no>';
//        $param .= '<total_fee>' . $amount . '</total_fee>';
//        $param .= '<refund_fee>' . $amount . '</refund_fee>';
//        //$param .= '<transaction_id></transaction_id>';
//        $param .= '<sign_type>MD5</sign_type>';
//        $param .= '<sign>' . $signStr . '</sign>';
//        $param .= '</xml>';
//        $res = $this->db->refundWx($uid, $out_refund_no, $orderno, $amount, $param);
//        if ($res['code'] < 0) {
//            return array('code' => -2, 'msg' => $res['msg'], 'data' => $res);
//        }
//        $resWx = $this->toCurl($httpUrl, $param, 1);
//        $this->db->refundModify($res['data'], $resWx);
//        if ($resWx['code'] < 0) {
//            return array('code' => -2, 'msg' => $resWx['msg'], 'data' => $res);
//        }
//        return array('code' => 0, 'msg' => 'success', 'data' => $resWx['data']);
//    }

    /**
     * 构建CURL请求，单线程
     * @param string $httpUrl 请求地址
     * @param string $string 参数拼接的字符串
     * @return $json
     */
    public function toCurl($httpUrl = '', $string = '', $is_ddd = 0)
    {
        $curl = curl_init(); //初始化
        curl_setopt($curl,CURLOPT_URL,$httpUrl);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($curl, CURLOPT_FORBID_REUSE, 1);
        curl_setopt($curl, CURLOPT_FRESH_CONNECT, 1);
        curl_setopt($curl, CURLOPT_ENCODING, '');
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $string);
        curl_setopt($curl, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json',
            'Content-Length: ' . strlen($string),
            'Accept: application/json'
        ));
        curl_setopt($curl, CURLOPT_TIMEOUT, 5);
        $output = curl_exec($curl);
        curl_close($curl);
        if ($is_ddd) ddd($output);
        if (!$output) {
            return array('code'=>-1, 'msg'=>'请求失败');
        }
        $items = $this->xml2arr($output);
        if ($items['code'] < 0) {
            return array('code' => -2,'msg' => 'XML解析错误', 'data' => $items);
        }
        return array('code' => 0,'msg' => 'success', 'data' => $items['data']);
    }

    //解析xml
    public function xml2arr($xml)
    {
        $items = [];
        ////////////////////////正则匹配
        $prefix = '<![CDATA['; $suffix = ']]>';
        //return_code
        $res = preg_match('/<return_code>(.*?)<\/return_code>/', $xml, $matches);
        if (!$res) {
            return array('code' => -2, 'msg' => 'return_code 缺失', 'data' => $xml);
        }
        $return_code = $matches[1];
        if (substr($return_code, 0, strlen($prefix)) == $prefix) {
            $return_code = substr($return_code, 9);
        }
        if (substr($return_code, -3) == $suffix) {
            $return_code = substr($return_code, 0, -3);
        }
        $items['return_code'] = $return_code;
        //result_code
        $res = preg_match('/<result_code>(.*?)<\/result_code>/', $xml, $matches);
        if (!$res) {
            return array('code' => -2, 'msg' => 'result_code 缺失', 'data' => $xml);
        }
        $result_code = $matches[1];
        if (substr($result_code, 0, strlen($prefix)) == $prefix) {
            $result_code = substr($result_code, 9);
        }
        if (substr($result_code, -3) == $suffix) {
            $result_code = substr($result_code, 0, -3);
        }
        $items['result_code'] = $result_code;
        //prepay_id
        $res = preg_match('/<prepay_id>(.*?)<\/prepay_id>/', $xml, $matches);
        if (!$res) {
            return array('code' => -2, 'msg' => 'prepay_id 缺失', 'data' => $xml);
        }
        $prepay_id = $matches[1];
        if (substr($prepay_id, 0, strlen($prefix)) == $prefix) {
            $prepay_id = substr($prepay_id, 9);
        }
        if (substr($prepay_id, -3) == $suffix) {
            $prepay_id = substr($prepay_id, 0, -3);
        }
        $items['prepay_id'] = $prepay_id;
        //return_msg
        $res = preg_match('/<return_msg>(.*?)<\/return_msg>/', $xml, $matches);
        if (!$res) {
            return array('code' => -2, 'msg' => 'prepay_id 缺失', 'data' => $xml);
        }
        $return_msg = $matches[1];
        if (substr($return_msg, 0, strlen($prefix)) == $prefix) {
            $return_msg = substr($return_msg, 9);
        }
        if (substr($return_msg, -3) == $suffix) {
            $return_msg = substr($return_msg, 0, -3);
        }
        $items['return_msg'] = $return_msg;
        //判断错误
        if ($return_code != 'SUCCESS' || $result_code != 'SUCCESS') {
            return array('code' => -2, 'msg' => $return_msg, 'data' => $xml);
        }
        return array('code' => 0, 'msg' => 'success', 'data' => $items);
    }
}